package movepaint.controller;

import java.awt.Desktop;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.RenderedImage;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import javax.swing.*;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import movepaint.view.APropos;
import movepaint.GestureRecognition;
import movepaint.stateMachine.InkMachine;
import movepaint.utils.Utilitaire;
import movepaint.utils.FiltreData;

/**
 * Classe qui regroupe les methodes pour effectuer les actions du menu.
 *
 * @author Paulino A.
 * @version 1.0
 */
public class MenuAction {
	/** Frame principale **/
	private GestureRecognition _frameMain = null;
    /** Filtre de données pour les options Ouvrir/Enregistrer **/
    private FiltreData _fd = null;
    /** Liste des extensions acceptées **/
    private final static String[] acceptedExtensions = {"GIF", "TIF", "TIFF", "JPEG", "JPG", "PNG"};
    /** Description des extension acceptées **/
    private final static String DESCRIPTION_EXTENSION = "Images (gif, tif, tiff, jpeg, jpg, png)";

    // Chemin du fichier temporaire utilisé pour l'impression
    private final static String PATH_TMP_FILE = System.getProperty("java.io.tmpdir") + "tmpFileToPrint.jpg";

    // Lien vers le site ou l'application est hébergée
    private final static String TEXT_URL_APPLICATION = "http://code.google.com/p/movepaint/";
    // Texte d'information d'ouverture du site ou l'appli est hébergée
    private final static String TEXT_OUVERTURE_URL_APPLICATION = "Ouverture de " + TEXT_URL_APPLICATION + " ...";
    // Texte d'informationn pour l'enregistrement d'un fichier
    private final static String TEXT_ENREGISTREMENT_FICHIER  = "Enregistrement du fichier ";
    private final static String TEXT_ENREGISTREMENT          = "Enregistrement en cours...";
    private final static String TEXT_EN_COURS                = " en cours...";
    private final static String TEXT_ENREGISTREMENT_OK       = "Le fichier a été correctement enregistré!";
    // Texte d'information pour l'ouverture de la documentation
    private final static String TEXT_OUVERTURE_DOC = "Ouverture de la documentation ...";
    // Texte d'information pour l'impression de la zone de dessin
    private final static String TEXT_IMPRESSION = "Impression en cours...";
    // Texte d'information pour la création d'un nouveau document
    private final static String TEXT_NOUVEAU_DOCUMENT = "Nouveau document créé!";
    // Texte d'information pour l'ouverture d'un nouveau document
    private final static String TEXT_OUVERTURE_IMAGE = "Ouverture d'une image...";
    private final static String TXT_OUVERTURE_IMAGE_DEBUT = "L'image ";
    private final static String TXT_OUVERTURE_IMAGE_FIN = " a été chargée!";

    
	// Erreur chargement du look&feel
	private final static String ERROR_LAF = "Impossible de charger le look&feel";
	// Erreur fonction non développée
	private final static String ERROR_NON_DISPONIBLE         = "La fonction n'a pas encore été développée..";
	private final static String ERROR_ENTETE_NON_DISPONIBLE  = "Fonction non développée";
    // Erreur de format lors du chargement/enregistrement d'une image
    private final static String ERROR_FORMAT         = "Ce format n'est pas accepté!";
    private final static String ERROR_FORMAT_ENTETE  = "Erreur de format";


	/**
	 *	Constructeur du MenuAction
	 *
	 *	@param frameMain
	 *			Référence a la frame principale de l'application
	 **/
	public MenuAction(GestureRecognition frameMain) {
		_frameMain = frameMain;

        // Liste des extensions acceptées
        ArrayList<String> listAcceptedData = new ArrayList<String>();
        for (String ext: acceptedExtensions)
            listAcceptedData.add(ext);


        // On autorise seulement les fichiers images
        _fd = new FiltreData(DESCRIPTION_EXTENSION, listAcceptedData);
	}

    /**
     * Ouverture du browser par défaurt de l'user pour le rediriger vers la
     * page d'accueil du site hébergeant l'application.
     */
    public void accueil() {
        // On vérifie que la classe Desktop soit bien supportée :
        if ( Desktop.isDesktopSupported() ) {
            // On récupère l'instance du desktop :
            Desktop desktop = Desktop.getDesktop();

            // On vérifie que la fonction browse est bien supportée :
            if (desktop.isSupported(Desktop.Action.BROWSE)) {
                //  On indique a la barre de statut qu'une tache est en cours
                _frameMain._statusBar.isWork(true);
                try {
                        // Et on lance l'application associé au protocole :
                        desktop.browse(new URI(TEXT_URL_APPLICATION));

                        // Info dans la barre de statut
                        _frameMain._statusBar.setStatusText(TEXT_OUVERTURE_URL_APPLICATION);
                } catch (URISyntaxException ex) {
                    Logger.getLogger(MenuAction.class.getName()).log(Level.SEVERE, null, ex);
                } catch (IOException ex) {
                    Logger.getLogger(MenuAction.class.getName()).log(Level.SEVERE, null, ex);
                }
                //  On indique a la barre de statut qu'une tache est terminée
                _frameMain._statusBar.isWork(false);

            }
        }
    }

	/**
	 *	Méthode qui change le look&feel de l'application
	 *
	 *	@param sourceName Le nom du L&F qui a été choisi
	 */
	public void changeLaF(String sourceName) {
    	// On récupère la Map contenant les L&F disponibles
    	Map <String, String>mapLaF = Utilitaire.getLookAndFeelsMap();

		// On récupère le L&F associé
		final String nameLaF = mapLaF.get (sourceName);

		// On met à jour le L&F dans l'EDT (Event Dispath Thread)
		SwingUtilities.invokeLater (new Runnable() {
			public void run() {
				try {
				   UIManager.setLookAndFeel(nameLaF);
				   SwingUtilities.updateComponentTreeUI(_frameMain);
				   //force chaque composant de la fenêtre à appeler sa méthode updateUI
				} catch (Exception e) {
					JOptionPane.showMessageDialog(_frameMain, ERROR_LAF, e.getMessage(), JOptionPane.ERROR_MESSAGE);
			 	}
			}
		});
	}

	/**
	 *	Méthode qui affiche la fenetre donnant des informations sur l'application
	 **/
	public void aPropos() {
		new APropos(_frameMain);
	}

    /**
     * Réalise une copie des figures sélectionnées
     * (chaque copie est translatée à côté de l'originale)
     */
    public void coller() {
        _frameMain.sm.pasteSelectedShapes();
    }

    /**
     * Copie les figures sélectionnées +  active la fonction <i>Coller</i> & <i>Supprimer</i>
     */
    public void copier() {
        _frameMain.sm.copySelectedShapes();
    }

    /**
     * Efface les figures sélectionnées +  active la fonction <i>Coller</i> & <i>Supprimer</i>
     */
    public void effacer() {
        _frameMain.deleteShapes(InkMachine.TAG_SHAPE_HOVERED);
    }

    /**
     * Enregistre le document en cours.
     * <br>
     * Si le document a déjà été enregistré dans un fichier, ce dernier est réutilisé.
     * <br>
     * Sinon, on ouvre une boîte de dialogue pour demander à l'user ou il veut l'enregistrer
     */
    public void enregistrer() {
        //  On indique a la barre de statut qu'une tache est en cours
        _frameMain._statusBar.isWork(true);

        if (_frameMain.file != null) {
            _frameMain._statusBar.setStatusText(TEXT_ENREGISTREMENT_FICHIER
                                                        + _frameMain.file.getName() + TEXT_EN_COURS);
            sauvegardeFichier();
        } else {
            _frameMain._statusBar.setStatusText(TEXT_ENREGISTREMENT);
            enregistrer_sous();
        }

        //  On indique a la barre de statut qu'une tache est terminée
        _frameMain._statusBar.isWork(false);
    }

    /**
     * Enregistre le document en cours.
     * <br>
     * On ouvre une boîte de dialogue pour demander à l'user ou il veut l'enregistrer.
     */
    public void enregistrer_sous() {
        //Create a file chooser
        JFileChooser fc = new JFileChooser();
        fc.setFileSelectionMode(JFileChooser.FILES_ONLY);

        // On autorise seulement les fichiers images
        fc.setAcceptAllFileFilterUsed(false);
        fc.addChoosableFileFilter(_fd);

        boolean isOk = true;
        do {
            int returnVal = fc.showSaveDialog(_frameMain);
            if (returnVal == JFileChooser.APPROVE_OPTION && _fd.accept(fc.getSelectedFile())) {
                _frameMain.file = fc.getSelectedFile();

                // On sauvegarde le fichier
                sauvegardeFichier();

                // Tout est OK, on active la fonctiion Enregistrer...
                isOk = true;
            } else if (returnVal == JFileChooser.APPROVE_OPTION && (!_fd.accept(fc.getSelectedFile()))) {
                JOptionPane.showMessageDialog(_frameMain, ERROR_FORMAT,
                                                ERROR_FORMAT_ENTETE, JOptionPane.ERROR_MESSAGE);
                isOk = false;
            } else {
                System.out.println("Save command cancelled by user.");
                isOk = true;
            }
        } while (!isOk);
    }

    /**
     * Ouvre la Javadoc avec l'application utilisée par défaut par l'user.
     */
    public void manuel() {
        // On vérifie que la classe Desktop soit bien supportée :
        if ( Desktop.isDesktopSupported() ) {
            // On récupère l'instance du desktop :
            Desktop desktop = Desktop.getDesktop();

            // On vérifie que la fonction Open est bien supportée :
            if (desktop.isSupported(Desktop.Action.OPEN)) {
                //  On indique a la barre de statut qu'une tache est en cours
                _frameMain._statusBar.isWork(true);
                try {
                        // Et on lance l'application associé au protocole :
                        desktop.open(new File(GestureRecognition.PATH_DOC));

                        // Info dans la barre de statut
                        _frameMain._statusBar.setStatusText(TEXT_OUVERTURE_DOC);
                } catch (IOException ex) {
                    Logger.getLogger(MenuAction.class.getName()).log(Level.SEVERE, null, ex);
                }
                //  On indique a la barre de statut qu'une tache est terminée
                _frameMain._statusBar.isWork(false);

            }
        }
    }

	/**
	 *	Méthode qui permet de quitter l'application
	 **/
	public void quitter() {
        _frameMain.dispose();

		// On quitte le programme
		System.exit(0);
	}

    /**
     * Impression du document actuel.
     * <br>
     * L'application génère un fichier temporaire dans lequel elle stoque le contenu du
     *  document. Ensuite, elle l'utilise pour l'impression et le supprime une fois la tâche effectuée.
     */
    public void imprimer() {
        // On vérifie que la classe Desktop soit bien supportée :
        if ( Desktop.isDesktopSupported() ) {
            // On récupère l'instance du desktop :
            Desktop desktop = Desktop.getDesktop();

            // On vérifie que la fonction print est bien supportée :
            if (desktop.isSupported(Desktop.Action.PRINT)) {
                //  On indique a la barre de statut qu'une tache est en cours
                _frameMain._statusBar.isWork(true);
                _frameMain._statusBar.setStatusText(TEXT_IMPRESSION);

                // On récup l'ancien path du file (s'il existe)
                String oldFile = null;
                if (_frameMain.file != null)
                    oldFile = _frameMain.file.getPath();

                // Sauvegarde dans un fichier tmp
                _frameMain.file = new File(PATH_TMP_FILE);
                sauvegardeFichier();

                try {
                    // On imprime
                    desktop.print(_frameMain.file);
                } catch (IOException ex) {
                    Logger.getLogger(MenuAction.class.getName()).log(Level.SEVERE, null, ex);
                } finally {
                    // On utilise l'ancien fichier
                    if (oldFile != null)
                        _frameMain.file = new File(oldFile);
                    else {
                        _frameMain.file.delete();
                        _frameMain.file = null;
                    }
                }

                //  On indique a la barre de statut qu'une tache est terminée
                _frameMain._statusBar.isWork(false);
            }
        }
    }

    /**
     * Supprime tous les éléments présents dans le panel
     */
    public void nouveau() {
        //  On indique a la barre de statut qu'une tache est en cours
        _frameMain._statusBar.isWork(true);

        _frameMain._statusBar.setStatusText(TEXT_NOUVEAU_DOCUMENT);
					SwingUtilities.invokeLater(new Runnable() {
						public void run() {
                            _frameMain.canvas.removeAllShapes();
                            _frameMain.createGestureRecognizedPanel();
                            _frameMain.sm.createComponents();
						}
					});


        _frameMain._statusBar.isWork(false);
    }

    /**
     * Ouvre une boîte de dialogue dans laquelle l'user peut choisir
     *  une image à charger dans l'application.
     */
    public void ouvrir() {
        //  On indique a la barre de statut qu'une tache est en cours
        _frameMain._statusBar.isWork(true);
        _frameMain._statusBar.setStatusText(TEXT_OUVERTURE_IMAGE);

        //Create a file chooser
        JFileChooser fc = new JFileChooser();
        fc.setFileSelectionMode(JFileChooser.FILES_ONLY);

        // On autorise seulement les fichiers images
        fc.setAcceptAllFileFilterUsed(false);
        fc.addChoosableFileFilter(_fd);

        boolean isOk = true;
        do {
            int returnVal = fc.showOpenDialog(_frameMain);
            if (returnVal == JFileChooser.APPROVE_OPTION && _fd.accept(fc.getSelectedFile())) {
                _frameMain.file = fc.getSelectedFile();

                // On charge l'image
                loadImage();

                // On indique que le fichieer est chargé
                _frameMain._statusBar.setStatusText(TXT_OUVERTURE_IMAGE_DEBUT + _frameMain.file.getName()
                                                        + TXT_OUVERTURE_IMAGE_FIN);

                // Tout est OK, on active la fonctiion Enregistrer...
                isOk = true;
            } else if (returnVal == JFileChooser.APPROVE_OPTION && (!_fd.accept(fc.getSelectedFile()))) {
                JOptionPane.showMessageDialog(_frameMain, ERROR_FORMAT,
                                                ERROR_FORMAT_ENTETE, JOptionPane.ERROR_MESSAGE);
                isOk = false;
            } else {
                System.out.println("Load command cancelled by user.");
                isOk = true;
            }
        } while (!isOk);

        //  On indique a la barre de statut qu'une tache est terminée
        _frameMain._statusBar.isWork(false);
    }

    /**
     * Ouvre le panel des préférences de l'application
     */
    public void preference() {
        JOptionPane.showMessageDialog(_frameMain, ERROR_NON_DISPONIBLE, ERROR_ENTETE_NON_DISPONIBLE, JOptionPane.ERROR_MESSAGE);
    }

    /**
     * Sélectionne tous les shapes du panel de dessin
     */
    public void tousSelectionner() {
        _frameMain.sm.selectAllShapes();
    }

    /**
     * Chargement de l'image choisi par l'user dans le canvas de dessin.
     */
    private void loadImage() {
        _frameMain.canvas.newImage(0, GestureRecognition.HEIGHT_TOOL + 30.0, _frameMain.file.getPath()).addTag(InkMachine.TAG_SHAPE).belowAll();
        _frameMain.createGestureRecognizedPanel();
        _frameMain.sm.createComponents();
    }

    /**
     * Sauvegarde du fichier choisi par l'user.
     */
    private void sauvegardeFichier() {
        // On cache les canvas du menu
        _frameMain.hideShapes(GestureRecognition.GESTE_TAG);

        System.out.println("Saving: " + _frameMain.file.getName());

        Image img = _frameMain.canvas.createImage(_frameMain.canvas.getWidth(),
                                                  _frameMain.canvas.getHeight());

        Graphics g = img.getGraphics();

        _frameMain.canvas.paint(g);

        // On sauvegarde l'image
        try {
            ImageIO.write((RenderedImage) img, _fd.getExtension(_frameMain.file), _frameMain.file);

            // On informe l'user
            _frameMain._statusBar.setStatusText(TEXT_ENREGISTREMENT_OK);
        } catch (IOException ex) {
            Logger.getLogger(MenuAction.class.getName()).log(Level.SEVERE, null, ex);
        } catch (Exception e) {
            Logger.getLogger(MenuAction.class.getName()).log(Level.SEVERE, null, e);
        }

        // On réaffiche les canvas du menu
        _frameMain.showShapes(GestureRecognition.GESTE_TAG);

    }
}


